﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using System.Collections.Specialized;

using Microsoft.Xna.Framework.Content.Pipeline;

using CPXMenuEditor.Properties;

namespace CPXMenuEditor.Forms
{
    public partial class PipelineAssemblies : Form
    {
        public PipelineAssemblies()
        {
            InitializeComponent();

            string error;
            if (Settings.Default.PipelineAssemblies == null)
                Settings.Default.PipelineAssemblies = new StringCollection();
            foreach (string assembly in Settings.Default.PipelineAssemblies)
                TryAddAssembly(assembly, out error);
        }

        private bool TryAddAssembly(string path, out string error)
        {
            try
            {
                Assembly assembly = Assembly.LoadFile(path);
                
                // Make sure the assembly has an Importer or Processor
                bool foundType = false;
                Type[] types = assembly.GetTypes();
                foreach (Type type in types)
                {
                    if (IsContentImporter(type) || IsContentProcessor(type))
                    {
                        foundType = true;
                        break;
                    }
                }
                foundType = true;

                if (foundType)
                {
                    listBox.Items.Add(new AssemblyInfo(path, assembly.GetName().Name));
                    error = string.Empty;
                    return true;
                }
                else
                {
                    error = "The assembly " + assembly.GetName().Name + " does not contain any Content Importers or Processors";
                    return false;
                }
            }
            catch (Exception exception)
            {
                error = exception.Message;
                return false;
            }
        }

        private void okButton_Click(object sender, EventArgs e)
        {
            Settings.Default.PipelineAssemblies.Clear();
            foreach (AssemblyInfo assembly in listBox.Items)
                Settings.Default.PipelineAssemblies.Add(assembly.Path);
            Settings.Default.Save();
        }

        private void addButton_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.AddExtension = true;
            dialog.AutoUpgradeEnabled = true;
            dialog.CheckFileExists = true;
            dialog.CheckPathExists = true;
            dialog.Filter = "Assembly Files (*.dll, *.exe)|*.dll;*.exe";
            dialog.Multiselect = true;
            dialog.SupportMultiDottedExtensions = true;
            dialog.Title = "Add Content Pipline Assembly...";
            if (dialog.ShowDialog(this) == DialogResult.OK)
            {
                string error = string.Empty;
                foreach (string filename in dialog.FileNames)
                    if (!TryAddAssembly(filename, out error))
                        MessageBox.Show(this, "Unable to use the assembly " + Path.GetFileName(filename) + ": " + error,
                                            MainFrm.AppName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void removeButton_Click(object sender, EventArgs e)
        {
            if (listBox.SelectedIndex != -1)
                listBox.Items.RemoveAt(listBox.SelectedIndex);
        }

        public static bool IsContentImporter(Type queryType)
        {
            if (queryType.BaseType == null)
                return false;
            else if (queryType.BaseType.IsGenericType && queryType.BaseType.GetGenericTypeDefinition() == typeof(ContentImporter<>))
                return true;
            else
                return IsContentImporter(queryType.BaseType);
        }

        public static bool IsContentProcessor(Type queryType)
        {
            if (queryType.BaseType == null)
                return false;
            else if (queryType.BaseType.IsGenericType && queryType.BaseType.GetGenericTypeDefinition() == typeof(ContentProcessor<,>))
                return true;
            else
                return IsContentProcessor(queryType.BaseType);
        }

        private struct AssemblyInfo
        {
            public string Path;
            public string Name;

            public AssemblyInfo(string path, string name)
            {
                Path = path;
                Name = name;
            }

            public override string ToString()
            {
                return Name;
            }
        }
    }
}
